function Duration(x::Base.Dates.Time)
    return Nanoseconds(x.instant.value)
end

@inline function isMonthYear(x::T) where T<:Base.Dates.Period
    return T === Month || T === Year
end

function Duration(x::CompoundPeriod)
    parts = x.periods
    nparts = length(parts)
    monthyear = map(isMonthYear, parts)
    notmonthyear = (!).(monthyear)
    mapped_months = map(months, parts[monthyear])
    mapped_nanosecs = map(nanoseconds, parts[notmonthyear])
    msum = sum(mapped_months)
    nsum = sum(mapped_nanosecs)
    return TimeSpan(nsum, msum)
end

function Duration(x::T) where T<:Union{Base.Dates.Month, Base.Dates.Year}
    return TimeSpan(Months(value(x)))
end

Duration(x::Week)  = Duration( x.value * NANOSECONDS_PER_WEEK)
Duration(x::Day)  = Duration( x.value * NANOSECONDS_PER_DAY)
Duration(x::Hour) = Duration( x.value * NANOSECONDS_PER_HOUR)
Duration(x::Minute) = Duration( x.value * NANOSECONDS_PER_MINUTE)
Duration(x::Second) = Duration( x.value * NANOSECONDS_PER_SECOND)
Duration(x::Millisecond) = Duration( x.value * NANOSECONDS_PER_MILLISECOND)
Duration(x::Microsecond) = Duration( x.value * NANOSECONDS_PER_MICROSECOND)
Duration(x::Nanosecond)  = Duration( x.value)

Duration(x::Weeks)  = Duration( x.value * NANOSECONDS_PER_WEEK)
Duration(x::Days)  = Duration( x.value * NANOSECONDS_PER_DAY)
Duration(x::Hours) = Duration( x.value * NANOSECONDS_PER_HOUR)
Duration(x::Minutes) = Duration( x.value * NANOSECONDS_PER_MINUTE)
Duration(x::Seconds) = Duration( x.value * NANOSECONDS_PER_SECOND)
Duration(x::Milliseconds) = Duration( x.value * NANOSECONDS_PER_MILLISECOND)
Duration(x::Microseconds) = Duration( x.value * NANOSECONDS_PER_MICROSECOND)
Duration(x::Nanoseconds)  = Duration( x.value)

function Duration(day::I=zero(I),
                  hour::I=zero(I), minute::I=zero(I), second::I=zero(I),
                  millisecond::I=zero(I), microsecond::I=zero(I),
                  nanosecond::I=zero(I)) where I<:Integer
    dnanosec = nanosecond
    dnanosec += microsecond * NANOSECONDS_PER_MICROSECOND
    dnanosec += millisecond * NANOSECONDS_PER_MILLISECOND
    dnanosec += second * NANOSECONDS_PER_SECOND
    dnanosec += minute * NANOSECONDS_PER_MINUTE
    dnanosec += hour * NANOSECONDS_PER_HOUR
    dnanosec += day * NANOSECONDS_PER_DAY
    return Duration(dnanosec)
end

Duration(str::String) = parse(Duration, str)

Base.convert(::Type{Duration}, x::Duration) = x

Base.convert(::Type{DateTime}, x::Duration) =
    error("use Clock(x::DateTime), not Duration(x::DateTime)")

#= 
   expressing a Clock as a Duration is supported
   the interval is taken from the first valid Clock value
=#
Duration(x::Clock) = x - Clock(FIRST_DATE)
